package com.yunpeng.aidevice.dao.service.impl;

import com.yunpeng.aidevice.common.constant.ConfigConstantValues;
import com.yunpeng.aidevice.common.dto.save.UserSaveDTO;
import com.yunpeng.aidevice.common.enums.ResultCodeEnum;
import com.yunpeng.aidevice.common.enums.UserStateEnum;
import com.yunpeng.aidevice.common.vo.user.MerchantLoginUserVO;
import com.yunpeng.aidevice.dao.constant.DictionariesConstant;
import com.yunpeng.aidevice.dao.mapper.entity.UserMapper;
import com.yunpeng.aidevice.dao.mapper.record.NoticeConfigMapper;
import com.yunpeng.aidevice.dao.mapper.relation.UserOwnPermissionMapper;
import com.yunpeng.aidevice.dao.mapper.relation.UserRoleMapper;
import com.yunpeng.aidevice.dao.model.MerchantCountDO;
import com.yunpeng.aidevice.dao.model.entity.MerchantDO;
import com.yunpeng.aidevice.dao.model.entity.OrganizationDO;
import com.yunpeng.aidevice.dao.model.entity.UserDO;
import com.yunpeng.aidevice.dao.service.ICodeGenerateCommonService;
import com.yunpeng.aidevice.dao.service.IOrganizationService;
import com.yunpeng.aidevice.dao.service.IUserService;
import com.yunpeng.aidevice.dao.util.RelationUpdateUtil;
import com.yunpeng.cache.util.DistributedLockHelper;
import com.yunpeng.common.exception.BizException;
import com.yunpeng.common.util.Md5Utils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;

/**
 * UserServiceImpl 用户服务实现
 *
 * @author : Moore(hemw)
 * @date : 2020-04-08
 */
@Service
public class UserServiceImpl implements IUserService {

    /**
     * 日志对象
     */
    private static final Logger LOGGER = LoggerFactory.getLogger(UserServiceImpl.class);

    private static final String DEFAULT_PASSWORD = "000000";

    /**
     * 当前服务的实体表名
     */
    private static final String TABLE_NAME = "t_ai_device_user";

    @Resource
    private ICodeGenerateCommonService codeGenerateCommonService;

    @Resource
    private UserMapper userMapper;

    @Resource
    private UserOwnPermissionMapper userOwnPermissionMapper;

    @Resource
    private IOrganizationService organizationService;

    @Resource
    private UserRoleMapper userRoleMapper;

    @Resource
    private NoticeConfigMapper noticeConfigMapper;

    @Override
    /**
     * 根据用户代码获取用户
     *
     * @param code           用户代码
     * @param merchantCode   商户代码
     * @param tenantCode     租户代码
     * @return
     */
    public UserDO getByCode(String code, String merchantCode, String tenantCode) {
        UserDO userDO = userMapper.getByCode(code);
        if (userDO == null) {
            return null;
        }
        boolean merchantEquals = false;
        if (merchantCode == null) {
            if (userDO.getMerchantCode() == null) {
                merchantEquals = true;
            }
        } else {
            merchantEquals = merchantCode.equals(userDO.getMerchantCode());
        }
        if (!merchantEquals) {
            return null;
        }
        if (tenantCode == null) {
            if (userDO.getTenantCode() == null) {
                return userDO;
            }
        } else {
            if (tenantCode.equals(userDO.getTenantCode())) {
                return userDO;
            }
        }
        return null;
    }


    @Override
    /**
     * 更新用户信息
     *
     * @param userSaveDTO  用户保存信息
     * @param operatorCode 操作人代码
     * @return
     */
    public Boolean updateBasicInfo(UserSaveDTO userSaveDTO, String operatorCode) {
        UserDO userDO = getByCode(userSaveDTO.getUserCode(), userSaveDTO.getMerchantCode(), userSaveDTO.getTenantCode());
        if (userDO == null || userDO.getId() == null) {
            LOGGER.error("could not get user info ,user code {}", userSaveDTO.getUserCode());
            throw new BizException(ResultCodeEnum.DATA_ACCESS_FAIL);
        }
        Integer phoneExists = userMapper.checkUserPhoneExists(userDO.getMerchantCode(), userSaveDTO.getTenantCode(), userSaveDTO.getPhone(), userDO.getCode());
        if (phoneExists != null && phoneExists.equals(1)) {
            LOGGER.error("exists same user phone ,user code {}", userSaveDTO.getUserCode());
            throw new BizException(ResultCodeEnum.EXISTS_PHONE_NUMBER_FAILED);
        }
        Map<String, Object> parameters = new HashMap<>(16);
        parameters.put("updater", operatorCode);
        parameters.put("update_time", new Date());
        boolean redundantUpdated = false;
        boolean updateOrg = false;
        //处理名称更新冗余
        if (userSaveDTO.getUserName() != null && !userDO.getName().equals(userSaveDTO.getUserName())) {
            parameters.put("name", userSaveDTO.getUserName());
            redundantUpdated = true;
        }
        //处理组织
        OrganizationDO organizationDO;
        if (StringUtils.isNotBlank(userSaveDTO.getOrgCode())) {
            organizationDO = organizationService.getByCode(userSaveDTO.getOrgCode(), userSaveDTO.getMerchantCode(), userSaveDTO.getTenantCode());
        } else if (StringUtils.isNotBlank(userSaveDTO.getOrgNumber())) {
            organizationDO = organizationService.getByNumber(userSaveDTO.getOrgNumber(), userSaveDTO.getMerchantCode(), userSaveDTO.getTenantCode());
        } else {
            throw new BizException(ResultCodeEnum.LACK_ORG_FAILED);
        }
        if (!organizationDO.getCode().equals(userDO.getOrganizationCode())) {
            parameters.put("organization_code", organizationDO.getCode());
            parameters.put("organization_path", organizationDO.getNodePath());
            parameters.put("organization_name", organizationDO.getName());
            updateOrg = true;
        }
        //处理用户编号
        if (!userDO.getNumber().equals(userSaveDTO.getUserNumber())) {
            if (userMapper.countNumberExistsExcludeCode(userSaveDTO.getUserNumber(), userDO.getCode(), userSaveDTO.getMerchantCode(), DictionariesConstant.INSTANCE.getDefaultTenantCode()) > 0) {
                LOGGER.error("save user info error ,has same user number: ");
                throw new BizException(ResultCodeEnum.EXISTS_NUMBER_FAILED);
            }
            parameters.put("number", userSaveDTO.getUserNumber());
        }
        //处理电话更新冗余
        if (!userDO.getPhone().equals(userSaveDTO.getPhone())) {
            parameters.put("phone", userSaveDTO.getPhone());
            redundantUpdated = true;
        }
        //处理邮箱更新冗余
        if (!userDO.getEmail().equals(userSaveDTO.getEmail())) {
            parameters.put("email", userSaveDTO.getEmail());
            redundantUpdated = true;
        }
        parameters.put("sex", userSaveDTO.getSex());
        parameters.put("invalid_date", userSaveDTO.getInvalidDate());
        if (userSaveDTO.getFaceImages() == null || userSaveDTO.getFaceImages().isEmpty()) {
            parameters.put("state", UserStateEnum.waitUpload.getValue());
            parameters.put("face_img_url", null);
        } else {
            parameters.put("face_img_url", userSaveDTO.getFaceImages().toJSONString());
            parameters.put("state", UserStateEnum.normal.getValue());
        }
        if (userSaveDTO.getMerchantDefaultUser() != null) {
            parameters.put("merchant_default_user", userSaveDTO.getMerchantDefaultUser());
        }
        //冗余更新
        if (redundantUpdated) {
            RelationUpdateUtil.INSTANCE.userInfoUpdatePush(userSaveDTO.getUserName(),
                    userSaveDTO.getPhone(), userSaveDTO.getEmail(), userDO.getCode());
            if (userDO.getMerchantDefaultUser()) {
                //更新商户负责人信息
                RelationUpdateUtil.INSTANCE.merchantDefaultUserInfoUpdatePush(userSaveDTO.getUserName(),
                        userSaveDTO.getPhone(), userSaveDTO.getEmail(), userDO.getMerchantCode(),
                        userDO.getTenantCode(), true);
            }
        }
        //更新用户组织信息
        if (updateOrg) {
            RelationUpdateUtil.INSTANCE.userOrgInfoUpdatePush(organizationDO.getName(), organizationDO.getCode(), userDO.getCode());
        }
        return userMapper.update(userDO.getId(), parameters) > 0;
    }

    @Override
    /**
     * 根据组织机构代码查询对应用户
     *
     * @param orgCode
     * @return
     */
    public List<UserDO> queryListByOrganization(String orgCode) {
        if (StringUtils.isBlank(orgCode)) {
            return null;
        }
        Map<String, Object> queryMap = new HashMap<>(16);
        queryMap.put("flag", 1);
        queryMap.put("organization_code", orgCode);
        queryMap.put("tenant_code", DictionariesConstant.INSTANCE.getDefaultTenantCode());
        return userMapper.queryForList(queryMap);
    }

    @Override
    /**
     * 新增用户
     *
     * @param userSaveDTO  用户保存信息
     * @param operatorCode 操作用户代码
     * @return
     */
    public Boolean addNewUser(UserSaveDTO userSaveDTO, String operatorCode) {
        if (getUserByNumber(userSaveDTO.getUserNumber(), userSaveDTO.getMerchantCode(), userSaveDTO.getTenantCode()) != null) {
            LOGGER.error("save user info error ,has same user number: ");
            throw new BizException(ResultCodeEnum.EXISTS_NUMBER_FAILED);
        }
        Integer phoneExists = userMapper.checkUserPhoneExists(userSaveDTO.getMerchantCode(), userSaveDTO.getTenantCode(), userSaveDTO.getPhone(), null);
        if (phoneExists != null && phoneExists.equals(1)) {
            LOGGER.error("exists same user phone ,user code {}", userSaveDTO.getUserCode());
            throw new BizException(ResultCodeEnum.EXISTS_PHONE_NUMBER_FAILED);
        }
        UserDO userDO = new UserDO();
        userDO.initForNew(operatorCode);
        userDO.setName(userSaveDTO.getUserName());
        OrganizationDO organizationDO = null;
        if (StringUtils.isNotBlank(userSaveDTO.getOrgCode())) {
            organizationDO = organizationService.getByCode(userSaveDTO.getOrgCode(), userSaveDTO.getMerchantCode(), userSaveDTO.getTenantCode());
        } else if (StringUtils.isNotBlank(userSaveDTO.getOrgNumber())) {
            organizationDO = organizationService.getByNumber(userSaveDTO.getOrgNumber(), userSaveDTO.getMerchantCode(), userSaveDTO.getTenantCode());
        }
        if (organizationDO != null) {
            userDO.setOrganizationCode(organizationDO.getCode());
            userDO.setOrganizationPath(organizationDO.getNodePath());
            userDO.setOrganizationName(organizationDO.getName());
        }
        userDO.setPhone(userSaveDTO.getPhone());
        userDO.setNumber(userSaveDTO.getUserNumber());
        //默认密码md5
        userDO.setPassword(Md5Utils.getMd5(DEFAULT_PASSWORD).toUpperCase());
        userDO.setSex(userSaveDTO.getSex());
        userDO.setEmail(userSaveDTO.getEmail());
        if (userSaveDTO.getFaceImages() == null || userSaveDTO.getFaceImages().isEmpty()) {
            userDO.setState(UserStateEnum.waitUpload.getValue());
        } else {
            userDO.setFaceImgUrl(userSaveDTO.getFaceImages().toJSONString());
            userDO.setState(UserStateEnum.normal.getValue());
        }
        userDO.setInvalidDate(userSaveDTO.getInvalidDate());
        userDO.setMerchantCode(userSaveDTO.getMerchantCode());
        if (userSaveDTO.getMerchantDefaultUser() != null) {
            userDO.setMerchantDefaultUser(userSaveDTO.getMerchantDefaultUser());
        } else {
            userDO.setMerchantDefaultUser(false);
        }
        if (DistributedLockHelper.INSTANCE.getLock(TABLE_NAME, ConfigConstantValues.APPLICATION_NAME)) {
            userDO.setCode(codeGenerateCommonService.generateCode(TABLE_NAME));
            try {
                userMapper.add(userDO);
                return true;
            } catch (Exception ex) {
                LOGGER.error("save user info error : {}", userDO, ex);
                throw new BizException(ResultCodeEnum.SAVE_DATA_FAILED);
            } finally {
                codeGenerateCommonService.holdCountMinus(TABLE_NAME);
                DistributedLockHelper.INSTANCE.unlock(TABLE_NAME, ConfigConstantValues.APPLICATION_NAME);
            }
        } else {
            return false;
        }
    }

    @Override
    /**
     * 更新用户绑定组织
     *
     * @param userCodes      用户代码集合
     * @param organizationDO 组织机构信息
     * @param operatorCode   操作人代码
     * @return
     */
    public Boolean userBindToOrganization(List<String> userCodes, OrganizationDO organizationDO, String operatorCode) {
        if (userCodes == null || userCodes.isEmpty()) {
            return false;
        }
        if (StringUtils.isBlank(operatorCode)) {
            return false;
        }
        if (organizationDO == null || organizationDO.getId() == null) {
            throw new BizException(ResultCodeEnum.NOT_EXISTS_DATA_FAILED, "组织机构不存在");
        }
        userMapper.userBindToOrganization(organizationDO.getCode(), organizationDO.getNodePath(), organizationDO.getName(), operatorCode,
                new Date(), userCodes, organizationDO.getMerchantCode(), organizationDO.getTenantCode());
        return true;
    }


    @Override
    /**
     * 统计权限关联用户数量
     *
     * @param permissionCode 二选一
     * @param userCode       二选一
     * @param now            当前时间
     * @return
     */
    public Integer countPermissionRelation(String permissionCode, String userCode, Date now) {
        if (StringUtils.isBlank(userCode) && StringUtils.isBlank(permissionCode)) {
            throw new BizException(ResultCodeEnum.PARAMETER_CHECK_FAILED, "必须有一个不为空");
        }
        return userOwnPermissionMapper.existsCount(permissionCode, userCode, now);
    }

    @Override
    /**
     * 根据用户编号获取用户对象
     *
     * @param number       用户编号
     * @param merchantCode 商户代码
     * @param tenantCode   租户代码
     * @return
     */
    public UserDO getUserByNumber(String number, String merchantCode, String tenantCode) {
        if (StringUtils.isBlank(number)) {
            throw new BizException(ResultCodeEnum.PARAMETER_CHECK_FAILED, "number不能为空");
        }
        if (StringUtils.isBlank(merchantCode)) {
            throw new BizException(ResultCodeEnum.PARAMETER_CHECK_FAILED, "merchantCode不能为空");
        }
        if (StringUtils.isBlank(tenantCode)) {
            throw new BizException(ResultCodeEnum.PARAMETER_CHECK_FAILED, "tenantCode不能为空");
        }
        return userMapper.getByNumber(number, merchantCode, tenantCode);
    }

    @Override
    /**
     * 禁用启用用户
     *
     * @param enable       启用/禁用
     * @param userCode     用户代码
     * @param merchantCode 商户代码
     * @param tenantCode   租户代码
     * @param operatorCode 操作人代码
     * @return
     */
    public Boolean enableOrDisableUser(Boolean enable, String userCode, String merchantCode, String tenantCode, String operatorCode) {
        if (enable == null) {
            return false;
        }
        if (StringUtils.isBlank(userCode)) {
            return false;
        }
        if (StringUtils.isBlank(merchantCode)) {
            return false;
        }
        if (StringUtils.isBlank(tenantCode)) {
            return false;
        }
        if (StringUtils.isBlank(operatorCode)) {
            return false;
        }
        UserDO userDO = userMapper.getByCode(userCode);
        if (!userDO.getMerchantCode().equals(merchantCode) || !userDO.getTenantCode().equals(tenantCode)) {
            throw new BizException(ResultCodeEnum.HAS_NOT_PERMISSION);
        }
        if (enable && userDO.getFaceImgUrl() == null) {
            throw new BizException(ResultCodeEnum.LACK_FACE_IMG_FAILED);
        }
        Map<String, Object> updateMap = new HashMap<>(16);
        updateMap.put("update_time", LocalDateTime.now());
        updateMap.put("updater", operatorCode);
        updateMap.put("state", UserStateEnum.disabled.getValue());
        if (enable) {
            updateMap.put("state", UserStateEnum.normal.getValue());
        }
        return userMapper.update(userDO.getId(), updateMap) > 0;
    }


    @Override
    /**
     * 根据商户获取用户列表（20000）
     *
     * @param merchantCode
     * @param tenantCode
     * @return
     */
    public List<UserDO> getUserByMerchant(String merchantCode, String tenantCode) {
        if (StringUtils.isBlank(merchantCode)) {
            return new ArrayList<>();
        }
        if (StringUtils.isBlank(tenantCode)) {
            return new ArrayList<>();
        }
        Map<String, Object> queryMap = new HashMap<>(16);
        queryMap.put("flag", 1);
        queryMap.put("merchant_code", merchantCode);
        queryMap.put("tenant_code", tenantCode);
        return userMapper.queryForList(queryMap);
    }

    @Override
    /**
     * 获取设备关联的用户信息
     *
     * @param deviceCode
     * @return
     */
    public List<UserDO> getDeviceRelationUsers(String deviceCode) {
        if (StringUtils.isBlank(deviceCode)) {
            return new ArrayList<>();
        }
        return userMapper.getDeviceRelationUsers(deviceCode);
    }


    @Override
    /**
     * 统计商户用户数量
     *
     * @param merchantCodes
     * @param tenantCode
     * @param state
     * @return
     */
    public List<MerchantCountDO> countByMerchant(List<String> merchantCodes, String tenantCode, String state) {
        return userMapper.countByMerchant(merchantCodes, tenantCode, state);
    }

    @Override
    /**
     * 删除用户
     *
     * @param userCode
     * @param merchantCode
     * @param tenantCode
     * @return
     */
    public Boolean removeUser(String userCode, String merchantCode, String tenantCode) {
        UserDO userDO = getByCode(userCode, merchantCode, tenantCode);
        if (userDO == null) {
            throw new BizException(ResultCodeEnum.NOT_EXISTS_DATA_FAILED, "不存在用户");
        }
        userMapper.delete(userDO.getId());
        try {
            userRoleMapper.deleteByUser(userCode);
            userOwnPermissionMapper.deleteByUser(userCode);
            noticeConfigMapper.deleteByUser(userCode);
        } catch (Exception ex) {
            LOGGER.error("execute delete user relation error ,ex:", ex);
        }
        return true;
    }

    @Override
    /**
     * 创建商户默认用户
     *
     * @param merchantDO
     * @param orgCode
     * @param operatorCode
     * @return
     */
    public Boolean addMerchantDefaultUser(MerchantDO merchantDO, String orgCode, String operatorCode) {
        UserSaveDTO userSaveDTO = new UserSaveDTO();
        userSaveDTO.setUserName(merchantDO.getMerchantUser());
        userSaveDTO.setUserNumber("001");
        userSaveDTO.setPhone(merchantDO.getMerchantUserPhone());
        userSaveDTO.setOrgCode(orgCode);
        userSaveDTO.setSex(2);
        userSaveDTO.setInvalidDate(LocalDateTime.now());
        userSaveDTO.setEmail(merchantDO.getMerchantUserEmail());
        //userSaveDTO.setFaceImages()
        userSaveDTO.setMerchantCode(merchantDO.getCode());
        userSaveDTO.setMerchantDefaultUser(true);
        userSaveDTO.setTenantCode(merchantDO.getTenantCode());
        try {
            addNewUser(userSaveDTO, operatorCode);
            return true;
        } catch (Exception ex) {
            LOGGER.error("add merchant default user error ,ex", ex);
        }
        return false;
    }

    @Override
    /**
     * 根据用户代码获取用户
     *
     * @param code 用户代码
     * @return
     */
    public UserDO getByCode(String code) {
        return userMapper.getByCode(code);
    }

    @Override
    /**
     * 获取商户默认用户
     *
     * @param merchantCode
     * @param tenantCode
     * @return
     */
    public UserDO getMerchantDefaultUser(String merchantCode, String tenantCode) {
        return userMapper.getMerchantDefaultUser(merchantCode, tenantCode);
    }

    @Override
    /**
     * 修改密码
     *
     * @param userCode        用户代码
     * @param historyPassword 历史密码
     * @param password        新密码
     * @return
     */
    public Boolean updatePassword(String userCode, String historyPassword, String password) {
        if (StringUtils.isBlank(userCode) || StringUtils.isBlank(password)) {
            return false;
        }
        UserDO userDO = userMapper.getByCode(userCode);
        if (userDO == null) {
            throw new BizException(ResultCodeEnum.NOT_EXISTS_DATA_FAILED);
        }
        String md5Password = Md5Utils.getMd5(password);
        String md5historyPassword = Md5Utils.getMd5(historyPassword).toUpperCase();
        if (!userDO.getPassword().equalsIgnoreCase(md5historyPassword)) {
            throw new BizException(ResultCodeEnum.PASSWORD_ERROR);
        }
        if (userDO.getPassword().equalsIgnoreCase(md5Password)) {
            return true;
        }
        Map<String, Object> updateParam = new HashMap<>(16);
        updateParam.put("updater", userCode);
        updateParam.put("update_time", LocalDateTime.now());
        updateParam.put("password", md5Password);
        return userMapper.update(userDO.getId(), updateParam) > 0;
    }

    @Override
    /**
     * 重置密码
     *
     * @param userCode     用户代码
     * @param merchantCode 商户代码
     * @return
     */
    public Boolean resetPassword(String userCode, String merchantCode) {
        if (StringUtils.isBlank(userCode)) {
            return false;
        }
        UserDO userDO = userMapper.getByCode(userCode);
        if (userDO == null) {
            throw new BizException(ResultCodeEnum.NOT_EXISTS_DATA_FAILED);
        }
        if (!merchantCode.equalsIgnoreCase(userDO.getMerchantCode())) {
            throw new BizException(ResultCodeEnum.HAS_NOT_PERMISSION);
        }
        String md5historyPassword = Md5Utils.getMd5(DEFAULT_PASSWORD).toUpperCase();
        Map<String, Object> updateParam = new HashMap<>(16);
        updateParam.put("updater", userCode);
        updateParam.put("update_time", LocalDateTime.now());
        updateParam.put("password", md5historyPassword);
        return userMapper.update(userDO.getId(), updateParam) > 0;
    }

    @Override
    /**
     * 根据用户电话号码精确匹配商户信息(作为登录选择)
     *
     * @param phone
     * @return
     */
    public List<MerchantLoginUserVO> getMerchantUserByPhone(String phone) {
        return userMapper.getMerchantUserByPhone(phone);
    }
}
